namespace PasswordEnumerator
{
    using Microsoft.VisualBasic;
    using Microsoft.VisualBasic.CompilerServices;
    using System;
    using System.Collections;
    using System.Diagnostics;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Text;

    public class Decompressor
    {
        private static long fTotalSize;
        private static long fUnpackedSize;
        private const short Headept1 = 0x80;
        private const short Headept2 = 0x100;
        public bool Headeptf;
        public const byte Maxrarerrorret = 0x15;
        private RARHead mheader;
        private string mPassword;
        private string mRARFile;
        public Collection mRARFiles;
        public IntPtr mRARHandle;
        private long mTotalArchiveSize;
        private long mTotalPackedSize;
        private const string MYLIB = "Unrar.dll";
        public int Openret2;
        public string Openretmsg2;
        private const int RAR_EXTRACT = 2;
        private const int RAR_OM_EXTRACT = 1;
        private const int RAR_OM_LIST = 0;
        private const int RAR_SKIP = 0;
        private const int RAR_TEST = 1;
        private const int RAR_VOL_ASK = 0;
        private const int RAR_VOL_NOTIFY = 1;
        public string Retmsg;
        public bool[] Retmsgflag;
        public int[] Theexitcd;
        public int Theexitcdn;
        private const int UCM_CHANGEVOLUME = 0;
        private const int UCM_NEEDPASSWORD = 2;
        private const int UCM_PROCESSDATA = 1;
        private RARHeaderDataEx uHeaderEx;
        private const short Upbd = 0x180;
        private RAROpenArchiveDataEx uRAREx;
        public bool Weneedend;

        public event OnUnpackEventHandler OnUnpack;

        public static  event UnpackingEventHandler Unpacking;

        public Decompressor(string RARFile)
        {
            this.Headeptf = false;
            this.Retmsgflag = new bool[0x16];
            this.Weneedend = false;
            this.mRARFile = RARFile;
            this.Init();
        }

         

        public Decompressor(string RARFile, string Password)
        {
            this.Headeptf = false;
            this.Retmsgflag = new bool[0x16];
            this.Weneedend = false;
            this.mRARFile = RARFile;
            this.mPassword = Password;
            this.Init();
        }

        private RAREntry FormatFileEntry()
        {
            RAREntry entry2;
            entry2.FileName = this.uHeaderEx.FileName;
            entry2.FileNameW = Encoding.Unicode.GetString(this.uHeaderEx.FileNameW);
            entry2.Flags = this.uHeaderEx.Flags;
            entry2.PackSize = this.MakeLong(this.uHeaderEx.PackSize, this.uHeaderEx.PackSizeHigh);
            entry2.UnpSize = this.MakeLong(this.uHeaderEx.UnpSize, this.uHeaderEx.UnpSizeHigh);
            entry2.HostOS = this.uHeaderEx.HostOS;
            entry2.FileCRC = this.uHeaderEx.FileCRC;
            entry2.FileTime = this.uHeaderEx.FileTime;
            entry2.UnpVer = this.uHeaderEx.UnpVer;
            entry2.Method = this.uHeaderEx.Method;
            entry2.FileAttr = this.uHeaderEx.FileAttr;
            return entry2;
        }

        private void Init()
        {
            IEnumerator enumerator;
            this.uRAREx.CmtBuf = Strings.Space(0x4000);
            this.uRAREx.CmtBufSize = 0x4000;
            this.uRAREx.ArcName = this.mRARFile;
            this.uHeaderEx.CmtBuf = Strings.Space(0x4000);
            this.mRARFiles = new Collection();
            this.LoadFileList();
            this.mTotalArchiveSize = 0L;
            try
            {
                enumerator = this.mRARFiles.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    RAREntry current = (RAREntry) enumerator.Current;
                    this.mTotalArchiveSize += current.UnpSize;
                }
            }
            finally
            {
                //if (enumerator is IDisposable)
                //{
                //    (enumerator as IDisposable).Dispose();
                //}
            }
        }

        private void LoadFileList()
        {
            try
            {
                this.uRAREx.OpenMode = 0;
                this.mRARHandle = RAROpenArchiveEx(ref this.uRAREx);
                //if (this.uRAREx.OpenResult != 0)
                //{
                //    this.OpenError((RarErrors) this.uRAREx.OpenResult, this.mRARFile);
                //}
                if (((this.uRAREx.Flags >= 0x80) & (this.uRAREx.Flags < 0x100)) | (this.uRAREx.Flags >= 0x180))
                {
                    this.Headeptf = true;
                }
                //if (this.mPassword != "")
                //{
                //    RARSetPassword(this.mRARHandle, this.mPassword);
                //}
                RARSetPassword(this.mRARHandle, this.mPassword);

                RARCallBack eP = new RARCallBack(this.RARCB);
                RARSetCallback(this.mRARHandle, eP, 0);
                int num = RARReadHeaderEx(this.mRARHandle, ref this.uHeaderEx);
                this.mheader.ArcName = this.uHeaderEx.ArcName;
                this.mheader.ArcNameW = Encoding.Unicode.GetString(this.uHeaderEx.ArcNameW);
                this.mheader.CmtBuf = this.uRAREx.CmtBuf;
                this.mheader.CmtBufSize = this.uRAREx.CmtBufSize;
                this.mheader.CmtSize = this.uRAREx.CmtSize;
                this.mheader.CmtState = this.uRAREx.CmtState;
                while (num == 0)
                {
                    RAREntry item = this.FormatFileEntry();
                    this.mRARFiles.Add(item, null, null, null);
                    int num2 = RARProcessFile(this.mRARHandle, 0,"d:", "");
                    if (num2 != 0)
                    {
                        this.ProcessError((RarErrors) num2, this.mPassword);
                        if (!this.Headeptf)
                        {
                            //RARPEModule.Israr = false;
                        }
                        return;
                    }
                    //RARPEModule.Israr = true;
                    num = RARReadHeaderEx(this.mRARHandle, ref this.uHeaderEx);
                }
                RARCloseArchive(this.mRARHandle);
                GC.KeepAlive(eP);
            }
            catch (Exception exception1)
            {
                ProjectData.SetProjectError(exception1);
                ProjectData.ClearProjectError();
            }
        }

        private long MakeLong(int iLow, int iHigh)
        {
            return Conversions.ToLong(Operators.AddObject(Interaction.IIf(iLow >= 0, iLow, iLow + 0x100000000L), iHigh << 0x20));
        }

        public void OpenError(RarErrors ErroNum, string ArcName)
        {
            string str = "";
            switch (ErroNum)
            {
                case RarErrors.ERAR_NO_MEMORY:
                    str = "内存不足，无法完成操作";
                    break;

                case RarErrors.ERAR_BAD_DATA:
                    str = ArcName + "：文件头损坏";
                    break;

                case RarErrors.ERAR_BAD_ARCHIVE:
                    str = ArcName + "：不是RAR文件";
                    break;

                case RarErrors.ERAR_UNKNOWN_FORMAT:
                    str = ArcName + "：文件头加密";
                    break;

                case RarErrors.ERAR_EOPEN:
                    str = "无法打开：" + ArcName;
                    break;

                default:
                    str = "打开 " + ArcName + " 时，发生未知错误，错误代码为：" + Conversions.ToString((int) ErroNum);
                    break;
            }
            //RARPEModule.Israr = false;
            this.Openret2 = (int) ErroNum;
            this.Openretmsg2 = str;
        }

        public bool ProcessAll(string szDest, int RARMMode)
        {
            bool flag=false;
            try
            {
                this.uRAREx.OpenMode = 1;
                this.mRARHandle = RAROpenArchiveEx(ref this.uRAREx);
                if (this.uRAREx.OpenResult != 0)
                {
                    //this.OpenError((RarErrors) this.uRAREx.OpenResult, this.mRARFile);
                }
                if (this.mPassword != "")
                {
                    RARSetPassword(this.mRARHandle, this.mPassword);
                }
                RARCallBack eP = new RARCallBack(this.RARCB);
                RARSetCallback(this.mRARHandle, eP, 0);
                for (int i = RARReadHeaderEx(this.mRARHandle, ref this.uHeaderEx); i == 0; i = RARReadHeaderEx(this.mRARHandle, ref this.uHeaderEx))
                {
                    RAREntry r = this.FormatFileEntry();
                    fTotalSize = r.UnpSize;
                    fUnpackedSize = 0L;
                    int num2 = RARProcessFile(this.mRARHandle, 2, szDest, "");
                    if (num2 != 0)
                    {
                        this.ProcessError((RarErrors) num2, this.mPassword);
                    }
                    if (this.Weneedend)
                    {
                        break;
                    }
                    OnUnpackEventHandler onUnpackEvent = this.OnUnpackEvent;
                    if (onUnpackEvent != null)
                    {
                        onUnpackEvent(r);
                    }
                }
                RARCloseArchive(this.mRARHandle);
                GC.KeepAlive(eP);
                flag = true;
            }
            catch (Exception exception1)
            {
                ProjectData.SetProjectError(exception1);
                ProjectData.ClearProjectError();
            }
            return flag;
        }

        public void ProcessError(RarErrors ErroNum, string thepass)
        {
            string str;
            switch (ErroNum)
            {
                case RarErrors.ERAR_NO_MEMORY:
                    str = "试验密码：" + this.mPassword + " 时，内存不足，未完成操作";
                    break;

                case RarErrors.ERAR_BAD_DATA:
                    str = this.mPassword + "：不是正确的密码";
                    this.Weneedend = true;
                    break;

                case RarErrors.ERAR_BAD_ARCHIVE:
                    str = "试验密码：" + this.mPassword + " 时，无效卷标";
                    break;

                case RarErrors.ERAR_UNKNOWN_FORMAT:
                    str = this.mRARFile + "：未知文件格式";
                    break;

                case RarErrors.ERAR_EOPEN:
                    str = "试验密码：" + this.mPassword + " 时，打开卷标发生错误";
                    break;

                case RarErrors.ERAR_ECREATE:
                    str = "试验密码：" + this.mPassword + " 时，创建文件发生错误";
                    break;

                case RarErrors.ERAR_ECLOSE:
                    str = "试验密码：" + this.mPassword + " 时，文件关闭错误";
                    break;

                case RarErrors.ERAR_EREAD:
                    str = "试验密码：" + this.mPassword + " 时，读取错误";
                    break;

                case RarErrors.ERAR_EWRITE:
                    str = "试验密码：" + this.mPassword + " 时，写入错误";
                    break;

                case RarErrors.ERAR_CANCELLED:
                    str = "已经取消尝试：" + this.mPassword;
                    break;

                default:
                    str = "发生未知错误，错误代码为：" + Conversions.ToString((int) ErroNum);
                    break;
            }
            this.Theexitcdn++;
            this.Theexitcd = (int[]) Utils.CopyArray((Array) this.Theexitcd, new int[this.Theexitcdn + 1]);
            this.Theexitcd[this.Theexitcdn] = (int) ErroNum;
            if (!this.Retmsgflag[(int) ErroNum])
            {
                this.Retmsgflag[(int) ErroNum] = true;
                if (this.Retmsg != "")
                {
                    this.Retmsg = this.Retmsg + "；" + str;
                }
                else
                {
                    this.Retmsg = str;
                }
            }
        }

        public int RARCB(short msg, int userdata, IntPtr P1, int P2)
        {
            int num=0;
            switch (msg)
            {
                case 0:
                    switch (P2)
                    {
                        case 0:
                        {
                            string str = Marshal.PtrToStringAnsi(P1);
                            if (Interaction.MsgBox("Load Volume:" + str, MsgBoxStyle.OkCancel, "") != MsgBoxResult.Ok)
                            {
                                return -1;
                            }
                            return 1;
                        }
                        case 1:
                            return 1;
                    }
                    return num;

                case 1:
                {
                    RarDisposition disposition = RarDisposition.OP_CONTINUE;
                    fUnpackedSize += P2;
                    UnpackingEventHandler unpackingEvent = UnpackingEvent;
                    if (unpackingEvent != null)
                    {
                        unpackingEvent(fTotalSize, fUnpackedSize, ref disposition);
                    }
                    switch (disposition)
                    {
                        case RarDisposition.OP_CANCEL:
                            return -1;
                    }
                    return 1;
                }
                case 2:
                {
                    string mPassword = this.mPassword;
                    byte[] bytes = Encoding.ASCII.GetBytes(mPassword + "\0");
                    P2 = mPassword.Length;
                    Marshal.Copy(bytes, 0, P1, bytes.Length);
                    return 1;
                }
            }
            Interaction.MsgBox("Ooops!!,I don't know what I should do here.", MsgBoxStyle.Information, "");
            return num;
        }

        [DllImport("Unrar.dll", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Ansi)]
        private static extern int RARCloseArchive(IntPtr hArcData);
        [DllImport("Unrar.dll", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Ansi)]
        public static extern int RARGetDllVersion();
        [DllImport("Unrar.dll", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Ansi)]
        private static extern IntPtr RAROpenArchive(ref RAROpenArchiveData ArchiveData);
        [DllImport("Unrar.dll", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Ansi)]
        private static extern IntPtr RAROpenArchiveEx(ref RAROpenArchiveDataEx ArchiveData);
        [DllImport("Unrar.dll", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Ansi)]
        private static extern int RARProcessFile(IntPtr hArcData, int Operation, string DestPath, string DestName);
        [DllImport("Unrar.dll", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Ansi)]
        private static extern int RARReadHeader(IntPtr hArcData, ref RARHeaderData HeaderData);
        [DllImport("Unrar.dll", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Ansi)]
        private static extern int RARReadHeaderEx(IntPtr hArcData, ref RARHeaderDataEx HeaderData);
        [DllImport("Unrar.dll", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Ansi)]
        private static extern void RARSetCallback(IntPtr hArcData, RARCallBack EP, int UserData);
        [DllImport("Unrar.dll", CallingConvention=CallingConvention.StdCall, CharSet=CharSet.Ansi)]
        private static extern void RARSetPassword(IntPtr hArcData, string Password);
        public bool UnPackAll(string fDest)
        {
            return this.ProcessAll(fDest, 2);
        }

        public Collection RARFiles
        {
            get
            {
                return this.mRARFiles;
            }
        }

        public RARHead RARHeader
        {
            get
            {
                return this.mheader;
            }
        }

        public int RARTotalFiles
        {
            get
            {
                return this.mRARFiles.Count;
            }
        }

        public long TotalArchiveSize
        {
            get
            {
                return this.mTotalArchiveSize;
            }
        }

        public delegate void OnUnpackEventHandler(Decompressor.RAREntry r);

        public delegate int RARCallBack(short msg, int userdata, IntPtr P1, int P2);

        public enum RarDisposition
        {
            OP_CANCEL = -1,
            OP_CONTINUE = 1
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct RAREntry
        {
            public string FileName;
            public string FileNameW;
            public int Flags;
            public long PackSize;
            public long UnpSize;
            public int HostOS;
            public int FileCRC;
            public int FileTime;
            public int UnpVer;
            public int Method;
            public int FileAttr;
        }

        public enum RarErrors
        {
            ERAR_BAD_ARCHIVE = 13,
            ERAR_BAD_DATA = 12,
            ERAR_CANCELLED = 0x15,
            ERAR_ECLOSE = 0x11,
            ERAR_ECREATE = 0x10,
            ERAR_END_ARCHIVE = 10,
            ERAR_EOPEN = 15,
            ERAR_EREAD = 0x12,
            ERAR_EWRITE = 0x13,
            ERAR_NO_MEMORY = 11,
            ERAR_SMALL_BUF = 20,
            ERAR_UNKNOWN_FORMAT = 14
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct RARHead
        {
            public string ArcName;
            public string ArcNameW;
            public string CmtBuf;
            public int CmtBufSize;
            public int CmtSize;
            public int CmtState;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct RARHeaderData
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst=260)]
            public string ArcName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst=260)]
            public string FileName;
            public int Flags;
            public int PackSize;
            public int UnpSize;
            public int HostOS;
            public int FileCRC;
            public int FileTime;
            public int UnpVer;
            public int Method;
            public int FileAttr;
            public string CmtBuf;
            public int CmtBufSize;
            public int CmtSize;
            public int CmtState;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct RARHeaderDataEx
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst=0x400)]
            public string ArcName;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst=0x800)]
            public byte[] ArcNameW;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst=0x400)]
            public string FileName;
            [MarshalAs(UnmanagedType.ByValArray, SizeConst=0x800)]
            public byte[] FileNameW;
            public int Flags;
            public int PackSize;
            public int PackSizeHigh;
            public int UnpSize;
            public int UnpSizeHigh;
            public int HostOS;
            public int FileCRC;
            public int FileTime;
            public int UnpVer;
            public int Method;
            public int FileAttr;
            public string CmtBuf;
            public int CmtBufSize;
            public int CmtSize;
            public int CmtState;
            [VBFixedArray(0x400)]
            public byte Reserved;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct RAROpenArchiveData
        {
            [VBFixedString(260)]
            public string ArcName;
            public int OpenMode;
            public int OpenResult;
            public string CmtBuf;
            public int CmtBufSize;
            public int CmtSize;
            public int CmtState;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct RAROpenArchiveDataEx
        {
            [VBFixedString(0x400)]
            public string ArcName;
            [VBFixedArray(0x800)]
            public byte[] ArcNameW;
            public int OpenMode;
            public int OpenResult;
            public string CmtBuf;
            public int CmtBufSize;
            public int CmtSize;
            public int CmtState;
            public int Flags;
            [VBFixedArray(0x20)]
            public byte Reserved;
        }

        public enum RarOperations
        {
            OP_EXTRACT,
            OP_TEST,
            OP_LIST
        }

        public delegate void UnpackingEventHandler(long fTotalSize, long fUnpackedSize, ref Decompressor.RarDisposition Disposition);

        public UnpackingEventHandler UnpackingEvent { get; set; }

        public OnUnpackEventHandler OnUnpackEvent { get; set; }
    }
}

